#include "../corelib/time_util.hh"
#include "unittest/unittest.hh"
#include <cstring>
#include <cstdlib>
#include <chrono>

using namespace kratos::corelib;

FIXTURE_BEGIN(TimeUtil)

constexpr static std::time_t time_2010_01_01_00_00_00_UTC = 1262304000; // UTC THIRSDAY
static std::time_t time_2010_01_01_00_00_00_CIVIL = 1262275200; // UTC+8, FRIDAY

CASE(TestGetDaysUTC) {
    ASSERT_TRUE(1 == TimeUtil::UTC::getDaysUTC(time_2010_01_01_00_00_00_UTC, time_2010_01_01_00_00_00_UTC + 86400));
    ASSERT_TRUE(2 == TimeUtil::UTC::getDaysUTC(time_2010_01_01_00_00_00_UTC, time_2010_01_01_00_00_00_UTC + 86400 * 2));
    ASSERT_TRUE(0 == TimeUtil::UTC::getDaysUTC(time_2010_01_01_00_00_00_UTC, time_2010_01_01_00_00_00_UTC + 86399));
}

CASE(TestGetDays) {
    ASSERT_TRUE(1 == TimeUtil::CIVIL::getDays(time_2010_01_01_00_00_00_CIVIL, time_2010_01_01_00_00_00_CIVIL + 86400));
    ASSERT_TRUE(2 == TimeUtil::CIVIL::getDays(time_2010_01_01_00_00_00_CIVIL, time_2010_01_01_00_00_00_CIVIL + 86400 * 2));
    ASSERT_TRUE(0 == TimeUtil::CIVIL::getDays(time_2010_01_01_00_00_00_CIVIL, time_2010_01_01_00_00_00_CIVIL + 86399));
}

CASE(TestGetTimestampFromDatetime) {
    Datetime dt;
    memset(&dt, 0, sizeof(dt));
    dt.year = 2010;
    dt.month = 1;
    dt.day = 1;
    ASSERT_TRUE(time_2010_01_01_00_00_00_CIVIL == TimeUtil::CIVIL::getTimestampFromDatetime(dt));
}

CASE(TestGetTimestampFromDatetimeUTC) {
    Datetime dt;
    memset(&dt, 0, sizeof(dt));
    dt.year = 2010;
    dt.month = 1;
    dt.day = 1;
    ASSERT_TRUE(time_2010_01_01_00_00_00_UTC == TimeUtil::UTC::getTimestampFromDatetimeUTC(dt));
}

CASE(TestInSameDay) {
    ASSERT_FALSE(TimeUtil::CIVIL::inSameDay(time_2010_01_01_00_00_00_CIVIL, time_2010_01_01_00_00_00_CIVIL - 1));
    ASSERT_TRUE(TimeUtil::CIVIL::inSameDay(time_2010_01_01_00_00_00_CIVIL, time_2010_01_01_00_00_00_CIVIL));
    ASSERT_TRUE(TimeUtil::CIVIL::inSameDay(time_2010_01_01_00_00_00_CIVIL, time_2010_01_01_00_00_00_CIVIL + 1));
    ASSERT_FALSE(TimeUtil::CIVIL::inSameDay(time_2010_01_01_00_00_00_CIVIL, time_2010_01_01_00_00_00_CIVIL + 86400));
}

CASE(TestInSameDayUTC) {
    ASSERT_FALSE(TimeUtil::UTC::inSameDayUTC(time_2010_01_01_00_00_00_UTC, time_2010_01_01_00_00_00_UTC - 1));
    ASSERT_TRUE(TimeUtil::UTC::inSameDayUTC(time_2010_01_01_00_00_00_UTC, time_2010_01_01_00_00_00_UTC));
    ASSERT_TRUE(TimeUtil::UTC::inSameDayUTC(time_2010_01_01_00_00_00_UTC, time_2010_01_01_00_00_00_UTC + 1));
    ASSERT_FALSE(TimeUtil::UTC::inSameDayUTC(time_2010_01_01_00_00_00_UTC, time_2010_01_01_00_00_00_UTC + 86400));
}

CASE(TestInSameWeek) {
    ASSERT_TRUE(TimeUtil::CIVIL::inSameWeek(time_2010_01_01_00_00_00_CIVIL, time_2010_01_01_00_00_00_CIVIL));
    ASSERT_TRUE(TimeUtil::CIVIL::inSameWeek(time_2010_01_01_00_00_00_CIVIL, time_2010_01_01_00_00_00_CIVIL + 86400));
    ASSERT_TRUE(TimeUtil::CIVIL::inSameWeek(time_2010_01_01_00_00_00_CIVIL, time_2010_01_01_00_00_00_CIVIL + 86400 * 2));
    ASSERT_FALSE(TimeUtil::CIVIL::inSameWeek(time_2010_01_01_00_00_00_CIVIL, time_2010_01_01_00_00_00_CIVIL + 86400 * 3));
}

CASE(TestInSameWeekUTC) {
    ASSERT_TRUE(TimeUtil::CIVIL::inSameWeek(time_2010_01_01_00_00_00_UTC, time_2010_01_01_00_00_00_UTC));
    ASSERT_TRUE(TimeUtil::CIVIL::inSameWeek(time_2010_01_01_00_00_00_UTC, time_2010_01_01_00_00_00_UTC + 86400));
    ASSERT_TRUE(TimeUtil::CIVIL::inSameWeek(time_2010_01_01_00_00_00_UTC, time_2010_01_01_00_00_00_UTC + 86400 * 2));
    ASSERT_FALSE(TimeUtil::CIVIL::inSameWeek(time_2010_01_01_00_00_00_UTC, time_2010_01_01_00_00_00_UTC + 86400 * 3 - 60 * 60 * 8));
    ASSERT_TRUE(TimeUtil::CIVIL::inSameWeek(time_2010_01_01_00_00_00_UTC, time_2010_01_01_00_00_00_UTC + 86400 * 3 - 60 * 60 * 8 - 1));
}

CASE(TestDatetime) {
    Datetime dt({ 2010, 1, 1, 0, 0, 0 });
    ASSERT_TRUE(time_2010_01_01_00_00_00_CIVIL == dt.getTimestamp());
    ASSERT_TRUE(time_2010_01_01_00_00_00_UTC == dt.getTimestampUTC());

    Datetime dt1("2010/01/01 00:00:00");
    ASSERT_TRUE(time_2010_01_01_00_00_00_CIVIL == dt1.getTimestamp());
    ASSERT_TRUE(time_2010_01_01_00_00_00_UTC == dt1.getTimestampUTC());
    ASSERT_TRUE("2010/01/01 00:00:00" == dt1.getDateString());

    auto dt2 = TimeUtil::CIVIL::getDatetime(time_2010_01_01_00_00_00_CIVIL);
    ASSERT_TRUE(time_2010_01_01_00_00_00_CIVIL == dt2.getTimestamp());

    auto dt3 = TimeUtil::UTC::getDatetimeUTC(time_2010_01_01_00_00_00_UTC);
    ASSERT_TRUE(time_2010_01_01_00_00_00_UTC == dt3.getTimestampUTC());
}

FIXTURE_END(TimeUtil)
